#include "StdAfx.h"
#include "PropertyReader.h"
#include <sstream>

#pragma comment(lib, "propsys.lib")

#define PARSER_ENTRY(FUNCTION, KEYNAME) \
	m_parsers[KEYNAME] = shared_ptr<CPropertyParser>(new CPropertyParser(&CPropertyReader::FUNCTION, L#KEYNAME))

CPropertyReader::CPropertyReader(void) 
{
	PARSER_ENTRY(ParseBoolean, UI_PKEY_Enabled);
	PARSER_ENTRY(ParseString, UI_PKEY_LabelDescription);
	PARSER_ENTRY(ParseString, UI_PKEY_Keytip);
	PARSER_ENTRY(ParseString, UI_PKEY_Label);
	PARSER_ENTRY(ParseString, UI_PKEY_TooltipDescription);
	PARSER_ENTRY(ParseString, UI_PKEY_TooltipTitle);
	PARSER_ENTRY(ParseImage, UI_PKEY_LargeImage);
	PARSER_ENTRY(ParseImage, UI_PKEY_LargeHighContrastImage);
	PARSER_ENTRY(ParseImage, UI_PKEY_SmallImage);
	PARSER_ENTRY(ParseImage, UI_PKEY_SmallHighContrastImage);
	PARSER_ENTRY(ParseUInt, UI_PKEY_CommandId);
	PARSER_ENTRY(ParseCollection, UI_PKEY_ItemsSource);
	PARSER_ENTRY(ParseCollection, UI_PKEY_Categories);
	PARSER_ENTRY(ParseUInt, UI_PKEY_CategoryId);
	PARSER_ENTRY(ParseUInt, UI_PKEY_SelectedItem);
	PARSER_ENTRY(ParseUInt, UI_PKEY_CommandType);
	PARSER_ENTRY(ParseImage, UI_PKEY_ItemImage);
	PARSER_ENTRY(ParseBoolean, UI_PKEY_BooleanValue);
	PARSER_ENTRY(ParseDecimal, UI_PKEY_DecimalValue);
	PARSER_ENTRY(ParseString, UI_PKEY_StringValue);
	PARSER_ENTRY(ParseDecimal, UI_PKEY_MaxValue);
	PARSER_ENTRY(ParseDecimal, UI_PKEY_MinValue);
	PARSER_ENTRY(ParseDecimal, UI_PKEY_Increment);
	PARSER_ENTRY(ParseUInt, UI_PKEY_DecimalPlaces);
	PARSER_ENTRY(ParseString, UI_PKEY_FormatString);
	PARSER_ENTRY(ParseString, UI_PKEY_RepresentativeString);
	PARSER_ENTRY(ParsePropertyStore, UI_PKEY_FontProperties);
	PARSER_ENTRY(ParseString, UI_PKEY_FontProperties_Family);
	PARSER_ENTRY(ParseDecimal, UI_PKEY_FontProperties_Size);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_Bold);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_Italic);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_Underline);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_Strikethrough);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_VerticalPositioning);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_ForegroundColor);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_BackgroundColor);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_ForegroundColorType);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_BackgroundColorType);
	PARSER_ENTRY(ParseSimplePropertySet, UI_PKEY_FontProperties_ChangedProperties);
	PARSER_ENTRY(ParseUInt, UI_PKEY_FontProperties_DeltaSize);
	PARSER_ENTRY(ParseArray, UI_PKEY_RecentItems);
	PARSER_ENTRY(ParseBoolean, UI_PKEY_Pinned);
	PARSER_ENTRY(ParseUInt, UI_PKEY_Color);
	PARSER_ENTRY(ParseUInt, UI_PKEY_ColorType);
	PARSER_ENTRY(ParseUInt, UI_PKEY_ColorMode);
	PARSER_ENTRY(ParseString, UI_PKEY_ThemeColorsCategoryLabel);
	PARSER_ENTRY(ParseString, UI_PKEY_StandardColorsCategoryLabel);
	PARSER_ENTRY(ParseString, UI_PKEY_RecentColorsCategoryLabel);
	PARSER_ENTRY(ParseString, UI_PKEY_AutomaticColorLabel);
	PARSER_ENTRY(ParseString, UI_PKEY_NoColorLabel);
	PARSER_ENTRY(ParseString, UI_PKEY_MoreColorsLabel);
	PARSER_ENTRY(ParseVector, UI_PKEY_ThemeColors);
	PARSER_ENTRY(ParseVector, UI_PKEY_StandardColors);
	PARSER_ENTRY(ParseVector, UI_PKEY_ThemeColorsTooltips);
	PARSER_ENTRY(ParseVector, UI_PKEY_StandardColorsTooltips);
	PARSER_ENTRY(ParseBoolean, UI_PKEY_Viewable);
	PARSER_ENTRY(ParseBoolean, UI_PKEY_Minimized);
	PARSER_ENTRY(ParseUInt, UI_PKEY_QuickAccessToolbarDock);
	PARSER_ENTRY(ParseContextAvailable, UI_PKEY_ContextAvailable);
	PARSER_ENTRY(ParseUInt, UI_PKEY_GlobalBackgroundColor);
	PARSER_ENTRY(ParseUInt, UI_PKEY_GlobalHighlightColor);
	PARSER_ENTRY(ParseUInt, UI_PKEY_GlobalTextColor);
}


shared_ptr<CProperty> CPropertyReader::ParseBoolean(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	BOOL val;
	UIPropertyToBoolean(*key, *propVariant, &val);
	prop->SetPropertyKeyValue(val ? L"True" : L"False");
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseString(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	PWSTR pText;

	UIPropertyToStringAlloc(*key, *propVariant, &pText);
	prop->SetPropertyKeyValue(pText);
	CoTaskMemFree(pText);
	return prop;

}

shared_ptr<CProperty> CPropertyReader::ParseImage(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	IUIImage *pUIImage;
	HBITMAP hBitmap;
	UIPropertyToImage(*key, *propVariant, &pUIImage);
	pUIImage->GetBitmap(&hBitmap);
	prop->SetBitmap(hBitmap);
	pUIImage->Release(); 
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseUInt(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	UINT val;
	UIPropertyToUInt32(*key, *propVariant, &val);

	basic_stringstream<wchar_t> text;
	text << val;
	prop->SetPropertyKeyValue(text.str());
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseContextAvailable(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	static PWCHAR contextAvailabilityText[] = {L"UI_CONTEXTAVAILABILITY_NOTAVAILABLE", L"UI_CONTEXTAVAILABILITY_AVAILABLE", L"UI_CONTEXTAVAILABILITY_ACTIVE"};

	UINT val;
	UIPropertyToUInt32(*key, *propVariant, &val);
	
	if (val < 0 || val > UI_CONTEXTAVAILABILITY_ACTIVE)
	{
		prop->SetPropertyKeyValue(L"Unknown state");
		return prop;
	}

	prop->SetPropertyKeyValue(contextAvailabilityText[val]);
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseCollection(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	prop->SetPropertyKeyValue(L"Collection Parsing: <<Not Implemented Yet>>");
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseDecimal(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	DECIMAL d;
	BSTR out;

	UIPropertyToDecimal(*key, *propVariant, &d);
	VarBstrFromDec(&d, 0, LOCALE_NOUSEROVERRIDE, &out);

	prop->SetPropertyKeyValue(out);
	SysFreeString(out);
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParsePropertyStore(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	prop->SetPropertyKeyValue(L"Property Store Parsing: <<Not Implemented Yet>>");
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseSimplePropertySet(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	prop->SetPropertyKeyValue(L"Property Set Parsing: <<Not Implemented Yet>>");
	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseArray(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	prop->SetPropertyKeyValue(L"Array Parsing: <<Not Implemented Yet>>");

	return prop;
}

shared_ptr<CProperty> CPropertyReader::ParseVector(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	prop->SetPropertyKeyValue(L"Vector Parsing: <<Not Implemented Yet>>");
	return prop;
}

const shared_ptr<CProperty> CPropertyParser::Parse(shared_ptr<CProperty> prop, const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet)
{
	return m_parseFunction(prop, key, propVariant, propertySet);
}


CPropertyReader::~CPropertyReader(void)
{
}

const shared_ptr<CProperty> CPropertyReader::Parse(const PROPERTYKEY *key, const PROPVARIANT *propVariant, const IUISimplePropertySet* propertySet /*= NULL*/)
{
	if (key == NULL || key->fmtid == GUID_NULL)
		return shared_ptr<CProperty>(new CProperty(L"Empty Key"));


	const shared_ptr<CPropertyParser> &parser = m_parsers[*key];
	shared_ptr<CProperty> prop = shared_ptr<CProperty>(new CProperty(parser->GetPropertyName()));

	if (propVariant == NULL || propVariant->vt == VT_EMPTY)
	{
		prop->SetPropertyKeyValue(L"Empty value");
		return prop;
	}

	return parser->Parse(prop, key, propVariant, propertySet);
}
